# PPH Production: Initialize firewall and start all services via PM2 (PowerShell)
# Usage: Run as Administrator. Save as UTF-8 with BOM. No Chinese characters to avoid codepage issues.

$ErrorActionPreference = 'Stop'

function Assert-Cmd([string]$cmd) {
  if (-not (Get-Command $cmd -ErrorAction SilentlyContinue)) {
    throw "Required command not found: $cmd"
  }
}

function Get-FreeTcpPort {
  $listener = New-Object System.Net.Sockets.TcpListener([System.Net.IPAddress]::Loopback,0)
  $listener.Start()
  $port = ($listener.LocalEndpoint).Port
  $listener.Stop()
  return $port
}

# 1) Resolve paths
$Root = Split-Path -Parent $MyInvocation.MyCommand.Definition
$Ecosystem = Join-Path $Root 'config\ecosystem.config.cjs'

Write-Host "[PPH] Root: $Root" -ForegroundColor Cyan
Write-Host "[PPH] Ecosystem: $Ecosystem" -ForegroundColor Cyan

# 2) Check Node/npm/npx
Assert-Cmd node
Assert-Cmd npm
Assert-Cmd npx

# 3) Open Windows Firewall ports (idempotent)
Try {
  Write-Host "[PPH] Opening Windows Firewall ports 3010/3011/3012 (TCP)..." -ForegroundColor Yellow
  # Using New-NetFirewallRule is idempotent when DisplayName duplicates; ignore errors
  New-NetFirewallRule -DisplayName 'PPH TCP 3010-3012' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 3010,3011,3012 -ErrorAction SilentlyContinue | Out-Null
} Catch {
  Write-Warning "[PPH] Failed to add firewall rules via PowerShell. Fallback to netsh."
  & netsh advfirewall firewall add rule name="PPH-Frontend-3010"   dir=in action=allow protocol=TCP localport=3010  | Out-Null
  & netsh advfirewall firewall add rule name="PPH-Backend-3011"    dir=in action=allow protocol=TCP localport=3011  | Out-Null
  & netsh advfirewall firewall add rule name="PPH-Management-3012" dir=in action=allow protocol=TCP localport=3012  | Out-Null
}

# 4) Bind PM2_HOME to project-local folder and restart daemon safely
$pm2Home = Join-Path $Root '.pm2'
$env:PM2_HOME = $pm2Home
Write-Host "[PPH] PM2_HOME = $pm2Home" -ForegroundColor Cyan

# Kill any existing global daemon (ignore errors)
try { & npx pm2 kill | Out-Null } catch { Write-Warning "[PPH] pm2 kill failed or no daemon running." }

# 5) Start all apps defined in ecosystem

# 7) Fallback: if EPERM persists, start a fresh PM2 with a unique socket (workaround for named pipe permission issues)
try {
  $sockPort = Get-FreeTcpPort
  Write-Host "[PPH] Fallback: starting PM2 with custom RPC port $sockPort" -ForegroundColor Yellow
  & npx pm2 start "$Ecosystem" --env production -- --rpc-port $sockPort
  Write-Host "[PPH] PM2 status after fallback:" -ForegroundColor Green
  & npx pm2 list
} catch {
  Write-Warning "[PPH] Fallback attempt failed: $($_.Exception.Message)"
}

Write-Host "[PPH] Starting all services with PM2..." -ForegroundColor Yellow
& npx pm2 start "$Ecosystem" --env production

# 6) Show status
Write-Host "[PPH] PM2 list:" -ForegroundColor Green
& npx pm2 list

Write-Host "[PPH] Done. Open http://localhost:3012 to access management UI." -ForegroundColor Green

